import { IpcUtil } from './../utils/ipcUtil'
import { IamInfo } from './iamInfo'
import { Route, RouteModel, RequestMethod } from './route'
import { Loggor } from './../loggor'
import { IamUtil, TokenStatus } from '../utils/iamUtil'
import { IpcRequest } from '../model/request'
import { AuthenErrorException } from '../exception/authenErrorException'
import { NotFoundException } from '../exception/notFoundException'
export class Router {
  private static readonly REQUEST_PATH: string = 'mainPath'
  static listen() {
    Route.loadMapping()
    IpcUtil.on(this.REQUEST_PATH, (requestId: string, ipcRequest: IpcRequest) => {
      this.requestLog(requestId, ipcRequest)
      this.checkRequestAndReturnRoute(ipcRequest, (route:RouteModel) => {
        this.callMethod(requestId, route, ipcRequest.params)
      })
    })
  }
  private static checkRequestAndReturnRoute(ipcRequest: IpcRequest, cb: Function): void {
    const uri = ipcRequest.headers.uri
    const filteredRoute = Route.routes.filter(
      item => item.uri === uri && RequestMethod[item.method] === ipcRequest.type
    )
    if (filteredRoute.length === 0) {
      throw new NotFoundException(uri)
    }
    const route = filteredRoute[0]
    if (route.isAuth) {
      IamUtil.verifyToken(ipcRequest.headers.token, (result: TokenStatus) => {
        if (result === TokenStatus.success) {
          IamUtil.getId(ipcRequest.headers.token, (id: string) => {
            IamInfo.id = id
            cb(route)
          })
        } else {
          throw new AuthenErrorException('please login')
        }
      })
    } else {
      cb(route)
    }
  }
  private static callMethod(requestId: string, route: RouteModel, params: any) {
    route.caller(params).then(
      (data: any) => {
        this.sender(requestId, 200, 'ok', data)
      },
      (error: Error) => {
        Loggor.error(error.message,error.stack)
        if (error instanceof AuthenErrorException) {
          this.sender(requestId, 401, 'not authen', error.message)
        } else if (error instanceof NotFoundException) {
          this.sender(requestId, 404, 'not found', error.message)
        } else {
          this.sender(requestId, 500, 'internal error', error.message)
        }
      }
    )
  }

  private static sender(requestId: string, code: number, message: string, data: any) {
    const reply = {
      code: code,
      message: message,
      data: data
    }
    IpcUtil.send(requestId, this.REQUEST_PATH, reply)
  }
  private static requestLog = (requestId: string, ipcRequest: IpcRequest) => {
    const splitMark = '\n---------------------------------'
    Loggor.log(
      splitMark,
      '\ntime: ',
      new Date(),
      '\nrequestId: ',
      requestId,
      '\nuri: ',
      ipcRequest.headers.uri,
      '\nmethod: ',
      ipcRequest.type,
      splitMark
    )
  }
}